# Incluyo modulo que contiene la clase 'agente'
from agente import *

import histogram
# Incluyo modulo para realizar ploteo
from ploteo import plotear
from globalVar import *

def main():
    global GLOBAL_VAR, agentes, FOLDERS, REGION_LABEL
    global K_VS_TIME, LOG_RADIO, VISILIBITY, LOGS
    
    # Limpio pantalla
    os.system('clear')
    # Cargo archivo de configuracion
    config = xml_parser(menu_choose_config())
    GLOBAL_VAR['CONFIG_FILE'] = config.name
    
    
    # Cargo datos de Screen
    GLOBAL_VAR['SCREEN_WIDTH'], GLOBAL_VAR['SCREEN_HEIGHT'] = config.get_screen_size()
    screen_name = config.get_screen_name()
    GLOBAL_VAR['GRAFICO'] = config.get_is_grafic()
    GLOBAL_VAR['masa'] = config.get_masa_agente()    
    fps = config.get_fps()
    
    # Cargo datos de Agentes
    agent_image_file = config.get_imagen()
    cant_agentes = config.get_cantidad_agentes()
    GLOBAL_VAR['CANT_AGENT'] = cant_agentes
    
    # Cargo las constantes necesarias para el calculo del gradiente
    load_gradient_constants(config)
    
    # Cargo las constantes de sensor de vision
    load_vis_constants(config)
    
    # Obtengo a que REGION de la FIG.1 del paper corresponde la simulacion
    region = get_region(GLOBAL_VAR['C_a'], GLOBAL_VAR['C_r'], \
            GLOBAL_VAR['l_a'], GLOBAL_VAR['l_r'])
    
    # Cargo valor de dt
    GLOBAL_VAR['dt'] = config.get_dt()
    
    # Calculo potencial maximo
    potencial = (GLOBAL_VAR['C_r'] - GLOBAL_VAR['C_a'])
    
    # Asigno una energia cinetica maxima al sistema
    if potencial < 0:
        MAX_KINETIC = 0.5 * -potencial
    else:
        MAX_KINETIC = 0.9 * potencial        
    
    print "POTANCIAL r=0 : ",potencial 
    print "MAX_KINETIC : ",MAX_KINETIC 
    
    # Defino la velocidad maxima de un agente
    MAX_VEL = math.sqrt(2*MAX_KINETIC)
    print "VEL MAXIMA : ",MAX_VEL
    
    if GLOBAL_VAR['GRAFICO']:
        # Inicializo modulos de pygame
        pygame.init()
        # Inicializo la ventana en que la que voy a mostrar la simulacion.
        screen = pygame.display.set_mode((GLOBAL_VAR['SCREEN_WIDTH'], GLOBAL_VAR['SCREEN_HEIGHT']))
        # Agrego el titulo de la ventana.
        pygame.display.set_caption(screen_name)
        # Defino el background de la ventana.
        #en un futuro
        #background = pygame.image.load('fondo').convert()
        background = pygame.Surface(screen.get_size())
        background = background.convert()
        background.fill((0,0,200))
        background_rect = background.get_rect()
    
    for i in range(cant_agentes):
        # Creo un nuevo agente
        agente_aux = Agente(agent_image_file)
        # Pregunto si las posiciones iniciales son random
        if config.get_is_random():
            N = 3
            center_x = center_y = 10
            circle = True
            # Pregunto si genero posiciones al azar en una region circular
            if circle:
                # Genero posiciones al azar en circulo de radio N*l_a
                [pos_x,pos_y] = rand_position_on_circle(N, center_x, center_y)
            else:
                # Genero posiciones al azar en cuadrado de lado N*l_a
                [pos_x,pos_y] = rand_position_on_square(N, center_x, center_y)
        else: 
            # Obtengo posicion inicial del agente
            pos_x, pos_y = config.get_position(i)
        
        # Situo agentes en posicion inicial
        agente_aux.situar_en( pos_x, pos_y)    

        # Genero una velocidad aleatoria
        vel = rand_velocity(MAX_VEL)
        
            
        # Le asigno al agente la velocidad inicial
        agente_aux.speed = vel
        
        # Agrupo todos los agentes
        agentes.append(agente_aux)
                
    if GLOBAL_VAR['GRAFICO']:
        # Agrupo a los agentes en un contenedor de pygame
        grupo_agentes = pygame.sprite.Group(agentes)
        # Creo un reloj para seguir el curso del tiempo
        clock = pygame.time.Clock()
      
    # Obtengo el path actual
    local_path = os.getcwd()
    
    # Genero el path del directorio donde se guardara el archivo de log
    log_path = local_path+'/'+FOLDERS[region-1]
    
    # Veo si existe el path log_path
    if not os.access(log_path, os.F_OK):
        # Creo el directorio pues no existe
        os.mkdir(log_path)
    
    # Creo el archivo log en el directorio que corresponde
    LOGS['log'] = Log(log_path+'/'+REGION_LABEL[region-1], 't')
    
    # Guardo parametros de vision para salvarlos en archivo de log
    vis_param = (';').join( ' '+k+': '+str(VISILIBITY[k]) for k in VISILIBITY.keys())
        
    # Cargo parametros Ca,Cr,la,lr,alpha,beta,circle,N,center
    param ='C_a : '+str(GLOBAL_VAR['C_a'])+' ; '+'C_r: '+str(GLOBAL_VAR['C_r'])+\
        ' ; l_a: '+str(GLOBAL_VAR['l_a'])+' ; l_r: '+str(GLOBAL_VAR['l_r'])+\
        ' ; alpha: '+str(GLOBAL_VAR['alpha'])+' ; beta: '+str(GLOBAL_VAR['beta'])\
        +' ; Circle: '+str(circle)+' ; N(pos): '+str(N)+' ; Center: ('+str(center_x)+', '+str(center_y)+')'

    param += vis_param
    
    LOGS['log'].update( param)
    
    # Cargo tiempo de simulacion
    simulation_time = config.get_simulation_time()
    
    # Defino segundo
    segundo = 1/GLOBAL_VAR['dt']
    
    # Genero path donde se guardara el log de K vs Time
    k_vs_t_path = log_path +'/'+K_VS_TIME

    # Veo si existe el path 
    if not os.access(k_vs_t_path, os.F_OK):
        # Creo el directorio pues no existe
        os.mkdir(k_vs_t_path)
    
    # Genero archivo de log para K vs Time
    LOGS['k_vs_time'] = Log(k_vs_t_path+'/'+(LOGS['log'].name).split('/')[-1])
    
       
    # Genero path donde se guardara el log con: 
    #       time, media del radio,  desviacion estandar del radio
    radio_path = log_path + '/' + LOG_RADIO

    # Veo si existe el path 
    if not os.access(radio_path, os.F_OK):
        # Creo el directorio pues no existe
        os.mkdir(radio_path)
    
    # Genero archivo de log para el tiempo, radio y su desviacion standard
    LOGS['radius'] = Log(radio_path+'/'+(LOGS['log'].name).split('/')[-1])
        
    # Cargo el delta k para el cual voy a considerar la K total estable
    # RECORDAR SACAR SIGUIENTE LINEA Y BORRAR DE .XML
    min_k_diff = config.get_kinetic_range()
    
    # Seteo iterador del tiempo de la simulacion
    time = 0    
    
    # Contador de diferencias chicas de la K total del sistema.
    k_counter = 0
    
    # Contador de diferencias chicas de la r
    r_counter = 0
    
    # Se guardaran los valores de K y R de los ultimos history/2 segundos
    history = 6
    k_time_history = r_time_history = 5
    k_slope = r_slope = 0.15
    
    # Arrays donde se guardara la informacion de los ultimos segundos
    k_array = []
    r_array = []
    x = []
    for i in range(history):
        k_array.append(0)
        r_array.append(0)
        x.append(i)
        
        
    while time < simulation_time*segundo and (k_counter < k_time_history )\
            and r_counter < r_time_history :
        
        # Calculo energia cinetica
        e_k = total_kinetic()
            
        # Guardo K vs Time en un archivo log correspondiente
        LOGS['k_vs_time'].update(str(time)+','+str(e_k))
            
        # Calculo el promedio del radio de los agentes
        r = get_media_radio(agentes)
        
        # Desviacion estandar de r
        desviacion_r = radius_desviacion_estandar(agentes)
        
        # Guardo valores de tiempo, media del radio y su desviacion estandar
        LOGS['radius'].update(str(time)+','+ str(r)+','+ str(desviacion_r))
        
        if time % (segundo / 2) == 0: # Si paso medio segundo
            # Imprimo tiempo actuar y tiempo total
            print str(time / segundo)+" segundos de "+str(simulation_time)
            
            # Imprimo energio cinetica total del sistema y media del radio
            print "Enegia Kinetic : ", e_k
            print "Media del radio ",r
            
            # Guardo valores en array
            # Muevo los valores una posicion para atras
            k_array[:len(k_array)-1] = k_array[1:len(k_array)]
            r_array[:len(r_array)-1] = r_array[1:len(r_array)]
            
            # Guardo nuevo valor de la K total del sistema en ultima posicion
            k_array[len(k_array)-1] = e_k
                
            # Guardo nuevo valor de R media en ultima posicion
            r_array[len(r_array)-1] = r
        
        if time % (3 * segundo) == 0: # Si pasaron 3 segundos
            
            # Chequeo la estabilidad del sistema con respecto a K
            k_counter = check_stability(x, k_array, k_slope, k_counter)
            
            # Chequeo la estabilidad del sistema con respecto a R
            r_counter = check_stability(x, r_array, r_slope, r_counter)
            
        if GLOBAL_VAR['GRAFICO']:
            # Mantengo la actualizacion grafica a la velocidad deseada
            clock.tick(fps)
            
            # Administro los eventos ocurridos
            input(pygame.event.get())
            
            # Dibujo el fondo
            screen.blit(background, (0,0))
            
        # Velocity Verlet
        for agente in agentes:
            
            # Actualizo la posicione
            agente.update_position()
            
        for agente in agentes:
            
            # Actualizo valores
            agente.update_values()
            
            # Actualizo la velocidad
            agente.update_velocity()
            
            # Guardo tiempo actual de simulacion y datos de agente en log
            LOGS['log'].update(str(time)+','+agente.get_data() )
            
            if GLOBAL_VAR['GRAFICO']:
                    
                # Dibujo la posicion del agente con un circulo
                pygame.draw.circle(screen, pygame.color.THECOLORS['white'],agente.posEscala(),5)
                
                if VISILIBITY['enable'] and VISILIBITY['visible_cone']:
                    # Obtengo la escala de renderizado
                    escala = agente.escala
                
                    # Obtengo los puntos del cono de vision
                    points = vis.points_of_polygon(agente.vis_polygon, escala)
                
                    # Dibujo el cono de vision
                    pygame.draw.polygon(screen, pygame.color.THECOLORS['red'], points, 1)
            
        if GLOBAL_VAR['GRAFICO']:
                
            # Dibujo a los agentes en mi screen
            #if not VISILIBITY['enable'] :
            #    grupo_agentes.draw(screen)
               
            # Muestro screen actualizado
            pygame.display.flip()
                
        # Aumento iterado de tiempo
        time += 1
    
    # Guardo estado final
    save_current_state()
    
    # Cierro archivos de log
    close_logs()
            
    # Pregunto si hacer snapshot o no
    snapshot = raw_input('Desea hacer un snapshot ahora? (s/n) ')
    if snapshot[0] == 's':
        # Hago el snapshot
        plotear(LOGS['log'].name)
        
    # Pregunto si hacer histograma o no
    hist = raw_input('Desea hacer un histograma ahora? (s/n) ')
    if hist[0] == 's':
        # Hago el histograma
        histogram.main(LOGS['log'].name)
        

if __name__ == "__main__":
    main()

